package cn.ronghuanet.car.service.impl;

import cn.ronghuanet.base.constants.CarConstants;
import cn.ronghuanet.base.util.BaiduAuditUtil;
import cn.ronghuanet.base.util.VelocityUtils;
import cn.ronghuanet.car.doc.CarDoc;
import cn.ronghuanet.car.domain.Car;
import cn.ronghuanet.car.domain.CarDetail;
import cn.ronghuanet.car.domain.CarOperateLog;
import cn.ronghuanet.car.domain.CarType;
import cn.ronghuanet.car.mapper.CarDetailMapper;
import cn.ronghuanet.car.mapper.CarMapper;
import cn.ronghuanet.car.mapper.CarOperateLogMapper;
import cn.ronghuanet.car.repository.CarDocRepository;
import cn.ronghuanet.car.service.ICarService;
import cn.ronghuanet.base.service.impl.IBaseServiceImpl;
import cn.ronghuanet.base.exception.ResponseCode;
import cn.ronghuanet.base.exception.RonghuaAssert;
import cn.ronghuanet.org.domain.Employee;
import cn.ronghuanet.org.domain.Shop;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lijie
 * @since 2023-08-21
 */
@Service
public class CarServiceImpl extends IBaseServiceImpl<Car> implements ICarService {

    @Autowired
    private CarDetailMapper carDetailMapper;

    @Autowired
    private CarMapper carMapper;

    @Autowired
    private CarOperateLogMapper logMapper;

    @Autowired
    private CarDocRepository carDocRepository;

    @Value("${ronghua.carDetail.templatePath}")
    private String templatePath;

    @Value("${ronghua.carDetail.targetPath}")
    private String targetPath;

    @Transactional
    @Override
    public void insert(Car car, Employee loginUser) {
        // 创建时间,状态(新增时默认是下架),店铺信息,销售人员
        car.setCreatetime(new Date());
        car.setState(CarConstants.CAR_STATE_OFFLINE);
        // 设置车辆所属的店铺信息,取当前登录人所属的店铺
        car.setShopId(loginUser.getShop().getId());
        car.setShopname(loginUser.getShop().getName());
        // 销售人员
        // 实现方案一: 前端弄个员工下拉框,选择所属的销售人员,传递到后端
        // 方案二: 后端获取当前登录人ID
        car.setSellerId(loginUser.getId());

        // 对车辆信息(标题,封面,基本信息)做审核,根据审核结果设置审核状态
        List<String> texts = Arrays.asList(car.getTitle(),car.getCarDetail().getInfo());
        List<String> imgs = Arrays.asList(car.getCover());
        Map<String, Object> censor = BaiduAuditUtil.censor(texts, imgs);
        Boolean flag = (Boolean)censor.get("success");
        if(flag){
            car.setAuditstate(CarConstants.CAR_AUDIT_STATE_SUCCESS);
        }else{
            car.setAuditstate(CarConstants.CAR_AUDIT_STATE_FAIL);
        }
        super.insert(car);

        // 新建CarDetail
        CarDetail carDetail = car.getCarDetail();
        carDetail.setCarId(car.getId());
        carDetail.setCartitle(car.getTitle());
        carDetailMapper.insert(carDetail);

        // 添加审核日志
        CarOperateLog log = new CarOperateLog();
        log.setCarId(car.getId());
        if(flag){
            log.setOperateType(CarConstants.CAR_OPERATE_TYPE_AUDIT_SUCCESS);
            log.setNote("系统审核通过!");
        }else{
            log.setOperateType(CarConstants.CAR_OPERATE_TYPE_AUDIT_FAIL);
            log.setNote(censor.get("message").toString());
        }
        log.setOperateId(0L);       // 自动审核的操作人不应该是当前登录人,而是null或者0,表示是系统审核
        log.setOperateTime(new Date());
        logMapper.insert(log);
    }

    /**
     * 上架
     * @param ids
     */
    @Transactional
    @Override
    public String onsale(List<Long> ids,Employee loginUser) {
        // 1 参数校验
        // 1.1 参数非空校验
        RonghuaAssert.isNotNull(ids, ResponseCode.RESPONSE_CODE_40013);

        // 1.2 做审核状态的校验
        // 问题? 如果前端选择了10条数据做上架,其中2条是未审核通过的,8条是审核通过的
        // 方案一: 如果其中只要有一个不满足条件,就直接返回给前端一个错误信息,就是说10条都不让上架   用户体验度不是很好
        // 方案二: 将满足条件的继续做上架,不满足条件的不做上架  这种方案必须给前端一个明确的提示: 当前一共xx条,成功xx条,失败xx条
        // 1.2.1 根据ids批量查询
        List<Car> list = carMapper.loadByIds(ids);
        // 1.2.2 找到list集合中满足上架条件的数据
        list = list.stream().filter(x -> x.getState() == CarConstants.CAR_STATE_OFFLINE
                && x.getAuditstate() == CarConstants.CAR_AUDIT_STATE_SUCCESS).collect(Collectors.toList());
        // 如果当前没有满足条件的上架数据,要抛出异常
        RonghuaAssert.isNotNull(list,ResponseCode.RESPONSE_CODE_40015);

        // 2 修改当前满足条件的车辆数据的数据库的状态=上架,并添加上架时间
        List<Long> idList = list.stream().map(Car::getId).collect(Collectors.toList());
        carMapper.onsale(idList,CarConstants.CAR_STATE_ONLINE);

        // 3 添加上架日志  当前上架的有几条数据,就要新增几条日志
        saveLog(loginUser, idList,CarConstants.CAR_OPERATE_TYPE_ONLINE);

        // 4 将数据添加到es中 有数据库和其他中间件操作时,先操作数据库
        List<CarDoc> docs = getCarDocsByCar(list);
        carDocRepository.saveAll(docs);

        String msg = "当前一共%s条,成功%s条,失败%s条";
        msg = String.format(msg,ids.size(),idList.size(),(ids.size() - idList.size()));

        // 给上架的车辆生成详情页 每个上架车辆有自己的详情页
        // 为了后续访问页面时,能找到自己的页面,固定路径+carId.html
        for (CarDoc doc : docs) {
            String path  = this.targetPath+"\\"+doc.getId()+".html";
            VelocityUtils.staticByTemplate(doc,this.templatePath,path);
        }
        return msg;
    }

    private List<CarDoc> getCarDocsByCar(List<Car> list) {
        List<CarDoc> docs = new ArrayList<>();
        for (Car car : list) {
            CarDoc doc = new CarDoc();
            BeanUtils.copyProperties(car,doc);
            // 处理车辆的店铺
            Shop shop = car.getShop();
            if(Objects.nonNull(shop)){
                doc.setShopName(shop.getName());
                doc.setShopAddress(shop.getAddress());
                GeoPoint geoPoint = new GeoPoint(shop.getLat(), shop.getLon());
                doc.setShopPoint(geoPoint);
            }

            // 处理车辆的类型
            CarType carType = car.getCarType();
            if(Objects.nonNull(carType)){
                doc.setTypeName(carType.getName());
            }

            // 处理详情信息
            CarDetail carDetail = car.getCarDetail();
            if(Objects.nonNull(carDetail)){
                doc.setCarInfo(carDetail.getInfo());
            }
            docs.add(doc);
        }
        return docs;
    }


    /**
     * 下架
     * @param ids
     */
    @Transactional
    @Override
    public void offsale(List<Long> ids,Employee loginUser) {
        // 1 参数校验
        // 1.1 参数非空校验
        // 下架没有必要做状态校验,下架状态再次改为下架,对结果没有影响
        RonghuaAssert.isNotNull(ids,ResponseCode.RESPONSE_CODE_40014);

        // 2 修改数据库的状态=下架,并添加下架时间
        carMapper.offsale(ids,CarConstants.CAR_STATE_OFFLINE);

        // 3 添加下架的日志
        saveLog(loginUser,ids,CarConstants.CAR_OPERATE_TYPE_OFFLINE);

        // 4 从es中删除要下架的车辆信息
        for (Long id : ids) {
            carDocRepository.deleteById(id);
        }

        // 5 下架时删除静态页面
        for (Long id : ids) {
            String path  = this.targetPath+"\\"+id+".html";
            File file = new File(path);
            if(file.exists()){
                file.delete();
            }
        }
    }


    private void saveLog(Employee loginUser, List<Long> idList,Integer operateType) {
        String state = operateType == CarConstants.CAR_OPERATE_TYPE_ONLINE ? "上架":"下架";
        String note = "%s"+state+"了id=%s的车辆";
        List<CarOperateLog> logs = new ArrayList<>();
        for (Long id : idList) {
            CarOperateLog log = new CarOperateLog();
            log.setCarId(id);
            log.setOperateType(operateType);
            log.setOperateTime(new Date());
            log.setOperateId(loginUser.getId()); // 取当前登录人的id
            log.setNote(String.format(note, loginUser.getRealName(),id));
            logs.add(log);
        }
        logMapper.batchInsert(logs);
    }
}
